home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / contrib / TLI-patch / src-server / winterp.c < prev   
Encoding:
C/C++ Source or Header  |  1991-04-24  |  55.6 KB  |  1,484 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         winterp.c
  5. * RCS:          $Header: winterp.c,v 1.10 91/03/25 03:59:22 mayer Exp $
  6. * Description:  WINTERP main() file.
  7. * Author:       Niels Mayer, HPLabs
  8. * Created:      Sat Jun 10 02:15:35 1989
  9. * Modified:     Mon Mar 25 03:59:07 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r4 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. **
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: winterp.c,v 1.10 91/03/25 03:59:22 mayer Exp $";
  42.  
  43. #include <stdio.h>
  44. #include <ctype.h>
  45.  
  46. #include "../src-server/config.h" /* define DEFAULT_UNIX_SOCKET_FILEPATH DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR, etc */
  47.  
  48. #if (defined(WINTERP_WANT_INET_SERVER) || defined(WINTERP_WANT_UNIX_SERVER))
  49. #include <sys/types.h>
  50. #if defined(TLI)
  51. #include <tiuser.h>
  52. extern int t_errno;
  53. #else
  54. #include <sys/socket.h>
  55. #endif /* defined(TLI) */
  56. #endif                /* (defined(WINTERP_WANT_INET_SERVER) || defined(WINTERP_WANT_UNIX_SERVER)) */
  57.  
  58. #ifdef WINTERP_WANT_INET_SERVER
  59. #include <netinet/in.h>
  60. #include <netdb.h>
  61. #endif                /* WINTERP_WANT_INET_SERVER */
  62.  
  63. #ifdef WINTERP_WANT_UNIX_SERVER
  64. #include <stdlib.h> /* for unlink() */
  65. #include <sys/un.h> /* for AF_UNIX sockets */
  66. #endif                /* WINTERP_WANT_UNIX_SERVER */
  67.  
  68. #include <X11/Intrinsic.h>
  69. #include <X11/Shell.h>
  70. #include <Xm/Xm.h>
  71. #ifdef WINTERP_MOTIF_11
  72. #include <Xm/Protocols.h>    /* <Xm/Protocols.h> location seems to have moved in 1.1 */
  73. #else
  74. #include <X11/Protocols.h>
  75. #endif                /* WINTERP_MOTIF_11 */
  76.  
  77. #include "winterp.h"
  78. #include "user_prefs.h"
  79. #include "xlisp/xlisp.h"
  80.  
  81.  
  82. /* forward declarations */
  83. static void Read_Eval_Print();
  84. static int  Read_From_Stream_Eval_And_Print();
  85. #ifdef WINTERP_WANT_INET_SERVER
  86. static void AF_INET_Read_Eval_Print();
  87. static int  Initialize_AF_INET_Server_Socket();
  88. #endif                /* WINTERP_WANT_INET_SERVER */
  89. #ifdef WINTERP_WANT_UNIX_SERVER
  90. static void AF_UNIX_Read_Eval_Print();
  91. static int  Initialize_AF_UNIX_Server_Socket();
  92. #endif                /* WINTERP_WANT_UNIX_SERVER */
  93. static void Winterp_Xtoolkit_Error_Handler();
  94. static void Winterp_Xtoolkit_Warning_Handler();
  95. static int  Winterp_Xlib_Error_Handler();
  96. void        Winterp_Application_Shell_WMDelete_Callback();
  97.  
  98. /* global variables */
  99. jmp_buf        top_level;
  100. CONTEXT        cntxt;
  101. int        read_eval_print_just_called;
  102. int        lisp_reader_hit_eof;
  103. char*        app_name = NULL;
  104. char*        app_class = NULL;
  105. #ifdef WINTERP_WANT_INET_SERVER
  106. static int    client_AF_INET_listen_socket = NULL;
  107. #endif                /* WINTERP_WANT_INET_SERVER */
  108. #ifdef WINTERP_WANT_UNIX_SERVER
  109. static int    client_AF_UNIX_listen_socket = NULL;
  110. #endif                /* WINTERP_WANT_UNIX_SERVER */
  111. Widget        toplevel_Wgt = NULL;
  112. XtAppContext    app_context = NULL;
  113. Display*    display;
  114. Window        root_win;
  115. Screen*        screen;
  116. Colormap    colormap;
  117. Atom        wm_delete_atom;
  118. Pixel        default_foreground_pixel, default_background_pixel;
  119. USER_PREFS_DATA user_prefs;    /* extern declared in user_prefs.h, really here */
  120. char        temptext[BUFSIZ]; /* a temporary text buffer, for sprintf() */
  121. Arg        _args[10];    /* for XtSetArg() macros in winterp.h */
  122. int        _num_args;    /* for XtSetArg() macros in winterp.h */
  123.  
  124. /* 
  125.  * Data on how user-customization resources are interpreted:
  126.  * this must be kept up to date with data structure USER_PREFS_DATA_PTR 
  127.  * in user_prefs.h
  128.  */
  129. static XtResource resources[] = {
  130.   /*
  131.    * The name of the file to load to initialize xlisp.
  132.    */
  133.   {"lispInitFile", "LispInitFile",
  134.      XmRString, sizeof(String),
  135.      XtOffset(USER_PREFS_DATA_PTR, lisp_init_file),
  136.      XmRString, (XtPointer) DEFAULT_LISP_INIT_FILE},
  137.  
  138.   /*
  139.    * The name of the file to output lisp transactions.
  140.    */
  141.   {"lispTranscriptFile", "LispTranscriptFile",
  142.      XmRString, sizeof(String),
  143.      XtOffset(USER_PREFS_DATA_PTR, lisp_transcript_file),
  144.      XmRString, (XtPointer) DEFAULT_LISP_TRANSCRIPT_FILE},
  145.  
  146.   /*
  147.    * The name of the default directory for 'load'. This is only
  148.    * used in cases where 'load' wasn't supplied a full
  149.    * filepath (i.e. a path beginning with '/' or '.').
  150.    *
  151.    * Note that "lispLibDir" should be the path to an existing directory with
  152.    * a trailing '/', e.g. "/usr/local/winterp/lisp-lib/". The default is
  153.    * "./" so as to simulate Xlisp's default load behavior.
  154.    * (See also w_utils.c:Wut_Prim_LOAD()).
  155.    */
  156.   {"lispLibDir", "LisplibDir",
  157.      XmRString, sizeof(String),
  158.      XtOffset(USER_PREFS_DATA_PTR, lisp_lib_dir),
  159.      XmRString, (XtPointer) DEFAULT_LISP_LIB_DIR},
  160.   
  161.   /*
  162.    * Setting this boolean to FALSE will allow WINTERP to startup
  163.    * without printing lots of output.
  164.    */
  165.   {"enableInitMsgs", "EnableInitMsgs",
  166.      XmRBoolean, sizeof(Boolean),
  167.      XtOffset(USER_PREFS_DATA_PTR, enable_init_msgs),
  168.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_INIT_MSGS},
  169.  
  170. #ifdef WINTERP_WANT_INET_SERVER
  171.   /*
  172.    * The port number of the widget interpreter lisp server.
  173.    */
  174.   {"servicePort", "ServicePort",
  175.      XmRInt, sizeof(int),
  176.      XtOffset(USER_PREFS_DATA_PTR, service_port),
  177.      XmRImmediate, (XtPointer) DEFAULT_INET_SERVICE_PORT},
  178.  
  179.   /*
  180.    * The service name of the widget interpreter lisp server.
  181.    */
  182.   {"serviceName", "ServiceName",
  183.      XmRString, sizeof(String),
  184.      XtOffset(USER_PREFS_DATA_PTR, service_name),
  185.      XmRString, (XtPointer) DEFAULT_INET_SERVICE_NAME},
  186.  
  187.   /*
  188.    * Setting this boolean to TRUE will start up WINTERP so that
  189.    * it will accept input from its INET Domain Server. Those worried about
  190.    * security when running winterp-based applications will want to
  191.    * set this to FALSE in the application defaults file for the application.
  192.    */
  193.   {"enableInetServer", "enableInetServer",
  194.      XmRBoolean, sizeof(Boolean),
  195.      XtOffset(USER_PREFS_DATA_PTR, enable_AF_INET_server),
  196.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_INET_SERVER},
  197. #endif                /* WINTERP_WANT_INET_SERVER */
  198.  
  199. #ifdef WINTERP_WANT_UNIX_SERVER
  200.   /*
  201.    * Setting this boolean to FALSE will start up WINTERP without
  202.    * it's Unix Domain server. Those worried about security when running
  203.    * winterp-based applications on a multi-user machine will want
  204.    * to set this in the  application defaults file for the application.
  205.    */
  206.   {"enableUnixServer", "enableUnixServer",
  207.      XmRBoolean, sizeof(Boolean),
  208.      XtOffset(USER_PREFS_DATA_PTR, enable_AF_UNIX_server),
  209.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_UNIX_SERVER},
  210.  
  211.   /*
  212.    * This is set to the full pathname for the AF_UNIX domain socket-file
  213.    */
  214.   {"unixSocketFilepath", "UnixSocketFilepath",
  215.      XmRString, sizeof(String),
  216.      XtOffset(USER_PREFS_DATA_PTR, unix_socket_filepath),
  217.      XmRString, (XtPointer) DEFAULT_UNIX_SOCKET_FILEPATH},
  218. #endif                /* WINTERP_WANT_UNIX_SERVER */
  219.  
  220.   /*
  221.    * Setting this boolean to FALSE will start up WINTERP
  222.    * with the Xtoolkit's default XtError handler -- any XtErrors
  223.    * will cause WINTERP to exit. By default, this is TRUE,
  224.    * which means that a lisp error will be signalled, and the
  225.    * call-sequence (or callback) that caused the error will
  226.    * terminate, however WINTERP will be able to execute other callbacks,
  227.    * input from the XLISP eval-server, etc. For interactive
  228.    * use, I suggest leaving this resource at the default TRUE;
  229.    * for delivered applications, you probably want to set this to
  230.    * FALSE.
  231.    */
  232.   {"enableXtErrorBreak", "EnableXtErrorBreak",
  233.      XmRBoolean, sizeof(Boolean),
  234.      XtOffset(USER_PREFS_DATA_PTR, enable_XtError_break),
  235.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_XT_ERROR_BREAK},
  236.  
  237.   /*
  238.    * Setting this boolean to FALSE will start up WINTERP
  239.    * with the Xtoolkit's default XtWarning handler -- any XtWarnings
  240.    * will just cause a message to be printed, execution will continue.
  241.    * By default, this is TRUE which means that a lisp error will be
  242.    * signalled, and the call-sequence (or callback)  that caused the error
  243.    * will terminate,  however WINTERP will be able to execute other
  244.    * callbacks, input from the XLISP eval-server, etc. For interactive
  245.    * use, I suggest leaving this resource at the default TRUE;
  246.    * for delivered applications, you probably want to set this to
  247.    * FALSE.
  248.    */
  249.   {"enableXtWarningBreak", "EnableXtWarningBreak",
  250.      XmRBoolean, sizeof(Boolean),
  251.      XtOffset(USER_PREFS_DATA_PTR, enable_XtWarning_break),
  252.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_XT_WARNING_BREAK},
  253.  
  254.   /*
  255.    * Setting this boolean to FALSE will start up WINTERP
  256.    * with the Xlib's default Error handler -- any XErrors
  257.    * will cause WINTERP to exit. By default, this is TRUE,
  258.    * which means that a lisp error will be signalled, and the
  259.    * call-sequence (or callback) that caused the error will
  260.    * terminate, however WINTERP will be able to execute other callbacks,
  261.    * input from the XLISP eval-server, etc. For interactive
  262.    * use, I suggest leaving this resource at the default TRUE;
  263.    * for delivered applications, you probably want to set this to
  264.    * FALSE.
  265.    */
  266.   {"enableXErrorBreak", "EnableXErrorBreak",
  267.      XmRBoolean, sizeof(Boolean),
  268.      XtOffset(USER_PREFS_DATA_PTR, enable_XError_break),
  269.      XmRImmediate, (XtPointer) DEFAULT_ENABLE_X_ERROR_BREAK}
  270. };
  271.  
  272. /*
  273.  * Table indicating how to set-from-the-command-line the application-specific
  274.  * resources specified in resources[] above.
  275.  */
  276. static XrmOptionDescRec commandline_options_table[] = {
  277.   {"-init_file",    ".lispInitFile",    XrmoptionSepArg, NULL},
  278.   {"-transcript_file",    ".lispTranscriptFile",    XrmoptionSepArg, NULL},
  279.   {"-lib_dir",        ".lispLibDir",        XrmoptionSepArg, NULL},
  280.   {"-no_init_msgs",    ".enableInitMsgs",    XrmoptionNoArg, "false"},
  281.   {"-enable_init_msgs",    ".enableInitMsgs",    XrmoptionNoArg, "true"},
  282. #ifdef WINTERP_WANT_INET_SERVER
  283.   {"-serv_port",    ".servicePort",        XrmoptionSepArg, NULL},
  284.   {"-serv_name",    ".serviceName",        XrmoptionSepArg, NULL},
  285.   {"-no_inet_server",    ".enableInetServer",    XrmoptionNoArg, "false"},
  286.   {"-enable_inet_server",".enableInetServer",    XrmoptionNoArg, "true"},
  287. #endif                /* WINTERP_WANT_INET_SERVER */
  288. #ifdef WINTERP_WANT_UNIX_SERVER
  289.   {"-no_unix_server",    ".enableUnixServer",    XrmoptionNoArg, "false"},
  290.   {"-enable_unix_server",".enableUnixServer",    XrmoptionNoArg, "true"},
  291.   {"-unix_socket_file",    ".unixSocketFilepath",    XrmoptionSepArg, NULL},
  292. #endif                /* WINTERP_WANT_UNIX_SERVER */
  293.   {"-no_xterr_brk",    ".enableXtErrorBreak",    XrmoptionNoArg, "false"},
  294.   {"-enable_xterr_brk",    ".enableXtErrorBreak",    XrmoptionNoArg, "true"},
  295.   {"-no_xtwarn_brk",    ".enableXtWarningBreak",XrmoptionNoArg, "false"},
  296.   {"-enable_xtwarn_brk",".enableXtWarningBreak",XrmoptionNoArg, "true"},
  297.   {"-no_xerr_brk",    ".enableXErrorBreak",    XrmoptionNoArg, "false"},
  298.   {"-enable_xerr_brk",    ".enableXErrorBreak",    XrmoptionNoArg, "true"}
  299. };
  300.  
  301. /*
  302.  * Setup an action table for winterp. Note that action procedure "Lisp"
  303.  * is a special action procedure that calls the lisp evaluator on the
  304.  * parameters of the action. A translation like
  305.  * "Ctrl<Key>K: Lisp(quack 1 2 3)" will evaluate '(quack 1 2 3)'
  306.  */
  307. extern void Wtx_Winterp_Lisp_Action_Proc(); /* w_txlations.c */
  308. static XtActionsRec winterp_action_table[] = {
  309.   {"Lisp", Wtx_Winterp_Lisp_Action_Proc}
  310. };
  311.  
  312.  
  313. /*******************************************************************************
  314.  * main - the main routine
  315.  ******************************************************************************/
  316. main(argc,argv)
  317.   int argc; char *argv[];
  318. {
  319.   extern LVAL true;
  320.   extern LVAL s_evalhook,s_applyhook;
  321.   extern FILE* osaopen();
  322.   extern FILE *tfp;
  323.   extern int xldebug;
  324.   extern int xltrcindent;
  325.   extern LVAL Wshl_WidgetID_To_WIDGETOBJ(); /* wc_SHELL.c */
  326.   extern void Wfu_Sanity_Check(); /* w_funtab.c */
  327.   char** original_argv;
  328.   int    original_argc;
  329.   XEvent event;
  330.  
  331.  
  332.   /*
  333.    * Trim directory path off of program name.
  334.    */
  335.   if ((app_name = rindex(argv[0], '/')) == NULL)
  336.     app_name = argv[0];
  337.   else
  338.     app_name++;
  339.  
  340.   /*
  341.    * Trim "Login Shell" from the program name
  342.    */
  343.   if (*app_name == '-')
  344.     app_name++;
  345.  
  346.   /*
  347.    * sanity check to ensure that the number of pointers to funtab entries in
  348.    * w_funtab.h correspond to the number of entries in w_funtab.c:funtab[].
  349.    */
  350.   Wfu_Funtab_Sanity_Check();
  351.  
  352.   /* 
  353.    * Make a copy of argv,argc to pass into
  354.    * 'toplevel_Wgt = XtAppCreateShell(...applicationShellWidgetClass...)'
  355.    * This is used by session managers so as to provide arguments to restart
  356.    * the application with the same arguments as the current invocation.
  357.    * We must make a copy here because XtOpenDisplay() modifies argv and argc
  358.    * and we twiddle argc/argv below.
  359.    */
  360.   original_argv = (char**) XtMalloc((unsigned) (argc + 1) * sizeof(char*));
  361.   for (original_argc = 0 ; original_argc < argc ; original_argc++)
  362.     original_argv[original_argc] = argv[original_argc];
  363.   original_argv[original_argc] = NULL;
  364.   
  365.   /*
  366.    * Special case the first argument on the command line... 
  367.    * If it is "-class <classname>", then use the next argument <classname> as the
  368.    * application class.  This kludge allows us to run winterp using a variable
  369.    * application class name, thus allowing us to use specify variable APP-DEFAULT
  370.    * files. (Hack submitted by Eric Blossom of HP Western Response Center Labs.)
  371.    */
  372.   app_class = "Winterp";
  373.   if ((argc >= 3) && (strcmp(argv[1], "-class") == 0)) {
  374.     app_class = argv[2];
  375.     argv[2] = argv[0];
  376.     argv += 2;
  377.     argc -= 2;
  378.   }
  379.  
  380.   /* 
  381.    * Initialize the toolkit
  382.    */
  383.   XtToolkitInitialize();
  384.  
  385.   /* 
  386.    * Initialize Resource converters: normally, these functions are called 
  387.    * from XtCreateWidget(), XtCreateManagedWidget(),  XtCreatePopupShell(), and
  388.    * XtAppCreateShell(); they only get called the first time you create a
  389.    * widget of class Primitive or Manager because they're called from the 
  390.    * ClassInitialize() procedure. With the way WINTERP's automatic resource
  391.    * converters work, you can end up asking for a resource conversion to occur
  392.    * before any ClassInitialize() procs are called, and that would cause errors
  393.    * like "X Toolkit Warning: No type converter registered for 'String' to ..."
  394.    */
  395.   XmRegisterConverters();    /* from Xm/ResConvert.c -- used in Manager, Primitive and Vendor ClassInitialize() */
  396.   _XmRegisterPixmapConverters(); /* from Xm/Visual.c -- used in Manager, Primitive and Vendor ClassInitialize() */
  397.  
  398.   /*
  399.    * Sanity check to ensure that the version of the Motif toolkit libraries
  400.    * used correspond to the Motif toolkit header <Xm/Xm.h>. This test is only valid
  401.    * after XmRegisterConverters() has been called.
  402.    */
  403.   if (xmUseVersion != XmVersion) { /* XmVersion def'd and xmUseVersion externed in <Xm/Xm.h> */
  404.     (void) fprintf(stderr, "%s: Fatal error: application must be recompiled with <Xm/Xm.h> matching libXm.a\n", app_name);
  405.     (void) fprintf(stderr, "\t\t(header version == %d, library version == %d)\n", XmVersion, xmUseVersion);
  406.     exit(1);
  407.   }
  408.  
  409.   app_context = XtCreateApplicationContext();
  410.   display = XtOpenDisplay(app_context, (String) NULL, app_name, app_class,
  411.               commandline_options_table, XtNumber(commandline_options_table),
  412.               &argc, argv);
  413.   if (!display)
  414.     xlfatal("Can't open display -- XtOpenDisplay() failed.");
  415.  
  416.   if (argc > 1) {        /* if argc!=0, then there are invalid arguments that didn't get parsed by XtOpenDisplay() */
  417.     (void) fprintf (stderr, "usage: %s [-class <classname>] [-init_file <file.lsp>]\n", app_name);
  418.     (void) fprintf (stderr, "\t[-transcript_file <file.out>] [-lib_dir <path-to-load-dir>]\n");
  419.     (void) fprintf (stderr, "\t[-no_init_msgs] [-enable_init_msgs]\n");
  420. #ifdef WINTERP_WANT_INET_SERVER
  421.     (void) fprintf (stderr, "\t[-serv_port <portnum>] [-serv_name <servname>]\n");
  422.     (void) fprintf (stderr, "\t[-no_inet_server] [-enable_inet_server]\n");
  423. #endif                /* WINTERP_WANT_INET_SERVER */
  424. #ifdef WINTERP_WANT_UNIX_SERVER
  425.     (void) fprintf (stderr, "\t[-no_unix_server] [-enable_unix_server]\n");
  426.     (void) fprintf (stderr, "\t[-unix_socket_file <socket-filepath>]\n");
  427. #endif                /* WINTERP_WANT_UNIX_SERVER */
  428.     (void) fprintf (stderr, "\t[-no_xterr_brk] [-enable_xterr_brk]\n");
  429.     (void) fprintf (stderr, "\t[-no_xtwarn_brk] [-enable_xtwarn_brk]\n");
  430.     (void) fprintf (stderr, "\t[-no_xerr_brk] [-enable_xerr_brk]\n");
  431.     (void) fprintf (stderr, "\t[... Xtoolkit options ...]\n");
  432.     (void) fprintf (stderr, "\tNote: if you wish to use the -class option it must be the\n");
  433.     (void) fprintf (stderr, "\tfirst argument following %s.\n", app_name);
  434.     xlfatal("Invalid command-line arguments.");
  435.   }
  436.  
  437.   /* 
  438.    * Set close-on-exec on file descriptor of display connection. Otherwise, any
  439.    * child processes started up by WINTERP will inherit the file-descriptor, and
  440.    * windows will not disappear after WINTERP is killed while child processes remain.
  441.    */
  442.   fcntl(ConnectionNumber(display), F_SETFD, 1);
  443.  
  444.   /*
  445.    * initialize some global variables used throughout this program.
  446.    * NOTE: if winterp ever gets changed to use application contexts enabling
  447.    * multiple displays, screens, etc, then we'll have to make some major changes
  448.    * here, and to any primitives that use these values.
  449.    */
  450.   root_win = DefaultRootWindow(display);
  451.   screen = DefaultScreenOfDisplay(display);
  452.   colormap = XDefaultColormapOfScreen(screen);
  453.   wm_delete_atom = XmInternAtom(display, "WM_DELETE_WINDOW", TRUE);
  454.  
  455.   /*
  456.    * Setup action table for accelerators and translations.
  457.    */
  458.   XtAppAddActions(app_context, winterp_action_table, XtNumber(winterp_action_table));
  459.   
  460.   /* 
  461.    * We need toplevel_Wgt so that we can have around a "default" set of X
  462.    * structures (colors, graphics contexts etc) for use by XtConvert()...
  463.    * this is a kludge. We also need this widget around in order to set
  464.    * Winterp-specific application resources in structure user_prefs.
  465.    *
  466.    * So as not to bother people with an uneccesary window, we create the
  467.    * window at location +1+1, then unmap it.
  468.    */
  469.   ARGLIST_RESET();
  470.   ARGLIST_ADD(XmNdeleteResponse, XmDO_NOTHING);    /* we handle wm deletion (f.kill) w/ XmAddWMProtocolCallback() below. */
  471.   ARGLIST_ADD(XmNscreen, (XtArgVal) screen);
  472.   ARGLIST_ADD(XmNargc, (XtArgVal) original_argc);
  473.   ARGLIST_ADD(XmNargv, (XtArgVal) original_argv);
  474.   ARGLIST_ADD(XmNgeometry, (XtArgVal) "10x10+1+1"); /* we don't want user to have to place this window, so give it a location; giving size prevents "Error: Shell widget winterp has zero width and/or height" */
  475.   toplevel_Wgt = XtAppCreateShell(app_name, app_class, applicationShellWidgetClass, display, ARGLIST());
  476.   XmAddWMProtocolCallback(toplevel_Wgt, wm_delete_atom, Winterp_Application_Shell_WMDelete_Callback, NULL);
  477.   XtGetApplicationResources(toplevel_Wgt, &user_prefs, resources, XtNumber(resources), NULL, 0); /* place application resources in user_prefs global struct. */
  478.   XtRealizeWidget(toplevel_Wgt); /* give the order to create the windows, etc. */
  479.   XmUpdateDisplay(toplevel_Wgt); /* after this executes, the widget will get realized, windows created, etc. */
  480.   XtUnmapWidget(toplevel_Wgt);    /* once the windows are created by XtRealizeWidget()/XmUpdateDisplay(), we may hide the window by unmapping */
  481.   XtFree((char*) original_argv); /* Motif makes a copy of this upon setting XmNargv resource however, if this is placed after XtAppCreateShell() call, you get a coredump... */
  482.  
  483.   /*
  484.    * Get Xtoolkit's default foreground and background Pixels, set globals
  485.    * to these values.
  486.    */
  487.   {
  488.     XrmValue from, to;
  489.  
  490.     from.size = (unsigned int) strlen(XtDefaultForeground) + 1;
  491.     from.addr = (caddr_t) XtDefaultForeground;
  492.     to.size = (unsigned int) sizeof(Pixel);
  493.     to.addr = (caddr_t) &default_foreground_pixel;
  494.     XtConvert(toplevel_Wgt, XmRString, &from, XmRPixel, &to);
  495.     if (to.addr == NULL)    /* error if conversion failed */
  496.       xlfatal("XtConvert() couldn't convert XtDefaultForeground to XmRPixel.");
  497.  
  498.     from.size = (unsigned int) strlen(XtDefaultBackground) + 1;
  499.     from.addr = (caddr_t) XtDefaultBackground;
  500.     to.size = (unsigned int) sizeof(Pixel);
  501.     to.addr = (caddr_t) &default_background_pixel;
  502.     XtConvert(toplevel_Wgt, XmRString, &from, XmRPixel, &to);
  503.     if (to.addr == NULL)    /* error if conversion failed */
  504.       xlfatal("XtConvert() couldn't convert XtDefaultBackground to XmRPixel.");
  505.   }
  506.  
  507. #ifdef WINTERP_WANT_INET_SERVER
  508.   if (user_prefs.enable_AF_INET_server) {
  509.     /*
  510.      * get a socket to listen on. when it's selected, call AF_INET_Read_Eval_Print()
  511.      * to open a connection socket, process the client request, and close the socket
  512.      */
  513.     client_AF_INET_listen_socket = Initialize_AF_INET_Server_Socket();
  514.     (void) XtAppAddInput(app_context, client_AF_INET_listen_socket, XtInputReadMask,
  515.              AF_INET_Read_Eval_Print, NULL);
  516.   }
  517. #endif                /* WINTERP_WANT_INET_SERVER */
  518.  
  519. #ifdef WINTERP_WANT_UNIX_SERVER
  520.   if (user_prefs.enable_AF_UNIX_server) {
  521.     /*
  522.      * get a socket to listen on. when it's selected, call AF_UNIX_Read_Eval_Print()
  523.      * to open a connection socket, process the client request, and close the socket
  524.      */
  525.     client_AF_UNIX_listen_socket = Initialize_AF_UNIX_Server_Socket();
  526.     (void) XtAppAddInput(app_context, client_AF_UNIX_listen_socket, XtInputReadMask,
  527.              AF_UNIX_Read_Eval_Print, NULL);
  528.   }
  529. #endif                /* WINTERP_WANT_UNIX_SERVER */
  530.  
  531.  
  532.   /*
  533.    * Setup Xlib and Xtoolkit warning and error handlers so that errors inside
  534.    * the Xtoolkit will call xlerror().
  535.    */
  536.   if (user_prefs.enable_XtError_break)
  537.     (void) XtAppSetErrorHandler(app_context, Winterp_Xtoolkit_Error_Handler);
  538.   if (user_prefs.enable_XtWarning_break)
  539.     (void) XtAppSetWarningHandler(app_context, Winterp_Xtoolkit_Warning_Handler);
  540.   if (user_prefs.enable_XError_break)
  541.     XSetErrorHandler(Winterp_Xlib_Error_Handler);
  542.  
  543.   if (user_prefs.enable_init_msgs) {
  544.     (void) printf("================================================================================\n");
  545. #ifdef WINTERP_MOTIF_111
  546.     (void) printf("WINTERP -- Motif 1.1.1 "); /* no way to tell 1.1.1 from 1.1, but the user may want to know... */
  547. #else                /* Plain old 1.0 or 1.1 */
  548.     (void) printf("WINTERP -- Motif %d.%d ", XmVERSION, XmREVISION); /* from <Xm/Xm.h> */
  549. #endif                /* WINTERP_MOTIF_111 */
  550.     (void) printf("Widget INTERPreter by Niels P. Mayer (mayer@hplabs.hp.com).\n");
  551.     (void) printf("    WINTERP version %d.%d, Copyright (c) 1989, 1990, 1991 Hewlett-Packard Company\n",
  552.           WINTERP_VERSION_INT, WINTERP_REVISION_INT); /* from winterp.h */
  553.     (void) printf("    XLISP version %d.%d, Copyright (c) 1989, by David Betz\n\n",
  554.           XLISP_VERSION_INT, XLISP_REVISION_INT); /* from xlisp/xlisp.h */
  555.   }
  556.  
  557.   /* 
  558.    * Startup XLISP
  559.    */
  560.   if (user_prefs.enable_init_msgs)
  561.     osinit("Initializing ...\n");
  562.   else 
  563.     osinit("");
  564.  
  565.   /* setup initialization error handler */
  566.   xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, (LVAL)1);
  567.   if (setjmp(cntxt.c_jmpbuf))
  568.     xlfatal("Fatal XLISP initialization error.");
  569.   if (setjmp(top_level))
  570.     xlfatal("XLISP RESTORE not allowed during initialization.");
  571.  
  572.   /* initialize xlisp */
  573.   xlinit();            /* xlisp/xlinit.c */
  574.  
  575.   /* initialize WINTERP modules */
  576.   Wso_Init();            /* w_savedobjs.c */
  577.   Wres_Init();            /* w_resources.c */
  578.   Wxms_Init();            /* w_XmString.c */
  579.   Wcb_Init();            /* w_callbacks.c */
  580.   Wto_Init();            /* w_timeouts.c */
  581.   Wtx_Init();            /* w_txlations.c */
  582.   Weh_Init();            /* w_evnthndlr.c */
  583.   Wxm_Init();            /* w_libXm.c */
  584.  
  585.   /* 
  586.    * The following create interfaces to all the motif widget-classes via
  587.    * xlisp classes, by calling Wcls_Create_Subclass_Of_WIDGET_CLASS()
  588.    * with o_WIDGET_CLASS (def'd in Wc_WIDGET_Init()) as their superclass.
  589.    * Methods on the specific widget classes correspond to 
  590.    * special operations pertaining to that class, and not to others. 
  591.    * These derived classes may override the 'Widget_Class' :isnew method 
  592.    * for cases where motif "convenience" functions are used to create the 
  593.    * widget. Additionally, since different classes generate different callback
  594.    * structures, certain widgetclasses may override the metaclass' :set_callback
  595.    * and :add_callback methods so as to allow dereferencing of the appropriate
  596.    * callback structure elements.
  597.    */
  598.   Wc_WIDGET_Init();        /* WIDGET_CLASS metaclass */
  599.   Wc_SHELL_Init();        /* SHELL and POPUP_SHELL metaclasses */
  600.   Wc_ArrowB_Init();
  601.   Wc_BulletinB_Init();
  602.   Wc_CascadeB_Init();
  603.   Wc_Command_Init();
  604.   Wc_DrawingA_Init();
  605.   Wc_DrawnB_Init();
  606.   Wc_FileSB_Init();
  607.   Wc_Form_Init();
  608.   Wc_Frame_Init();
  609.   Wc_Label_Init();
  610.   Wc_List_Init();
  611.   Wc_MainW_Init();
  612.   Wc_MessageB_Init();
  613.   Wc_PanewW_Init();
  614.   Wc_PushB_Init();
  615.   Wc_RowColumn_Init();
  616.   Wc_Scale_Init();
  617.   Wc_ScrollBar_Init();
  618.   Wc_ScrolledW_Init();
  619.   Wc_SelectioB_Init();
  620.   Wc_Separator_Init();
  621.   Wc_Text_Init();
  622.   Wc_ToggleB_Init();
  623. #ifdef HP_GRAPH_WIDGET
  624.   Wc_XmGraph_Init();
  625. #endif                /* HP_GRAPH_WIDGET */
  626.  
  627.   /*
  628.    * Make the toplevel_Wgt accessible from lisp as global *TOPLEVEL_WIDGET*.
  629.    * This code must occur after calling Wc_SHELL_Init(), and preferably after
  630.    * every WINTERP widget class initializer is called.
  631.    */
  632.   setvalue(xlenter("*TOPLEVEL_WIDGET*"), Wshl_WidgetID_To_WIDGETOBJ(toplevel_Wgt));
  633.  
  634.   /*
  635.    * Make XLISP, WINTERP, and MOTIF version info available within interpreter.
  636.    */
  637.   setvalue(xlenter("*XLISP_VERSION*"),
  638.        cvfixnum((FIXTYPE) XLISP_VERSION_INT)); /* XLISP_VERSION_INT from xlisp/xlisp.h */
  639.   setvalue(xlenter("*XLISP_REVISION*"),
  640.        cvfixnum((FIXTYPE) XLISP_REVISION_INT)); /* XLISP_REVISION_INT from xlisp/xlisp.h */
  641.   setvalue(xlenter("*MOTIF_VERSION*"),
  642.        cvfixnum((FIXTYPE) XmVERSION)); /* XmVERSION from <Xm/Xm.h> */
  643.   setvalue(xlenter("*MOTIF_REVISION*"),
  644.        cvfixnum((FIXTYPE) XmREVISION)); /* XmREVISION from <Xm/Xm.h> */
  645.   setvalue(xlenter("*WINTERP_VERSION*"),
  646.        cvfixnum((FIXTYPE) WINTERP_VERSION_INT)); /* WINTERP_VERSION_INT from winterp.h */
  647.   setvalue(xlenter("*WINTERP_REVISION*"),
  648.        cvfixnum((FIXTYPE) WINTERP_REVISION_INT)); /* WINTERP_REVISION_INT from winterp.h  */
  649.  
  650.   xlend(&cntxt);
  651.  
  652.   /* reset the error handler */
  653.   xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, true);
  654.  
  655.   /* open the transcript file */
  656.   if (user_prefs.lisp_transcript_file && (tfp = osaopen(user_prefs.lisp_transcript_file, "w")) == NULL) {
  657.     (void) sprintf(temptext, "error: can't open transcript file: \"%s\"",
  658.            user_prefs.lisp_transcript_file);
  659.     stdputstr(temptext);
  660.   }
  661.  
  662.   /* load file specified by resource "lispInitFile" (defaults to "init.lsp") */
  663.   if (setjmp(cntxt.c_jmpbuf) == 0) {
  664.     if (!xlload(user_prefs.lisp_init_file, user_prefs.enable_init_msgs, FALSE)) {
  665.       (void) sprintf(temptext,
  666.              "WINTERP warning -- couldn't load initialization file: \"%s\"\n\t\
  667. Check command-line argument \"-init_file\" or Xresource \".lispInitFile\"\n",
  668.              user_prefs.lisp_init_file);
  669.       stdputstr(temptext);
  670.     }
  671.   }
  672.  
  673.   if (user_prefs.enable_init_msgs) {
  674.  
  675. #ifdef WINTERP_WANT_INET_SERVER
  676.     if (user_prefs.enable_AF_INET_server) {
  677.       (void) printf("\nXLisp INET Domain eval-server ready for input");
  678.       if (user_prefs.service_port)
  679.     (void) printf(" on port %d .\n", user_prefs.service_port);
  680.       else
  681.     (void) printf(" using service=%s .\n", user_prefs.service_name);
  682.     }
  683. #endif                /* WINTERP_WANT_INET_SERVER */
  684.  
  685. #ifdef WINTERP_WANT_UNIX_SERVER
  686.     if (user_prefs.enable_AF_UNIX_server)
  687.       (void) printf("\nXLisp Unix Domain eval-server ready for input on socket %s .\n",
  688.             user_prefs.unix_socket_filepath);
  689. #endif                /* WINTERP_WANT_UNIX_SERVER */
  690.  
  691. #if (defined(WINTERP_WANT_INET_SERVER) && !defined(WINTERP_WANT_UNIX_SERVER))
  692.     if (user_prefs.enable_AF_INET_server)
  693.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  694. #endif
  695. #if (!defined(WINTERP_WANT_INET_SERVER) && defined(WINTERP_WANT_UNIX_SERVER))
  696.     if (user_prefs.enable_AF_UNIX_server)
  697.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  698. #endif
  699. #if (defined(WINTERP_WANT_INET_SERVER) && defined(WINTERP_WANT_UNIX_SERVER))
  700.     if ((user_prefs.enable_AF_INET_server) || (user_prefs.enable_AF_UNIX_server))
  701.       (void) printf("Note: INPUT TO XLISP EVALUATOR CANNOT BE ENTERED HERE!! (see winterp.doc)\n");
  702. #endif
  703.  
  704.     (void) printf("================================================================================\n");
  705.   }
  706.   
  707.   /* setup longjmp target for restore */
  708.   if (setjmp(top_level))
  709.     xlbegin(&cntxt, CF_TOPLEVEL|CF_CLEANUP|CF_BRKLEVEL, true);
  710.  
  711.   read_eval_print_just_called = TRUE; /* special initial cond */
  712.   lisp_reader_hit_eof = FALSE;
  713.  
  714.   /* Process X Events and Lisp client requests forever */
  715.   for (;;) {
  716.     /* 
  717.      * We need to setup a new error return only after each time that an XLISP 
  718.      * evaluation occurs. Therefore, we check for read_eval_print_just_called 
  719.      * (which is set by Read_Eval_Print()) and then clear it once the setjmp() 
  720.      * has been done. This avoids setting up an error return for each X event
  721.      * being processed in this loop. 
  722.      */
  723.     if (read_eval_print_just_called) {
  724.       read_eval_print_just_called = FALSE;
  725.       if (lisp_reader_hit_eof) 
  726.     break;
  727.       if (setjmp(cntxt.c_jmpbuf)) { /* longjmp target for error return */
  728.     setvalue(s_evalhook, NIL);
  729.     setvalue(s_applyhook, NIL);
  730.     xltrcindent = 0;
  731.     xldebug = 0;
  732.         xlflush();        /* needed if using (read)/(read-line) from stdin */ 
  733.       }
  734.       if (user_prefs.enable_init_msgs)
  735.     stdputstr("Xlisp-Eval-Result: "); /* use this to separate results of different evaluations */
  736.       fflush(stdout); fflush(stderr); /* otherwise output won't happen while blocked in XtAppNextEvent() */
  737.     }
  738.  
  739.     /*
  740.      * XtAppNextEvent() waits for Xevents, and while it is waiting, it will
  741.      * process inputs added via AtAppAddInput() or XtAppAddWorkProc(). Lisp 
  742.      * server input will cause Read_Eval_Print() to get called, and that
  743.      * procedure sets the globals lisp_reader_hit_eof and 
  744.      * read_eval_print_just_called. Read_Eval_Print() sends a bogus 
  745.      * XAnyEvent (event.type == 0) so as to force XtAppNextEvent() to return; 
  746.      * otherwise it would only return if a lisp evaluation caused X events 
  747.      * to be generated, which means that XLISP error returns for non-X 
  748.      * evaluations wouldn't get set up properly.
  749.      *
  750.      * XtDispatchEvent() will dispatch the actions from the events gathered
  751.      * by XtAppNextEvent(). Note that XtDispatchEvent() ignores the aforementioned
  752.      * bogus events: "if (event->type == 0) return;"
  753.      */
  754.     XtAppNextEvent(app_context, &event);
  755.     XtDispatchEvent(&event);
  756.   }
  757.   wrapup();            /* this is also called if we eval expr (quit) */
  758. }
  759.  
  760.  
  761. #ifdef WINTERP_WANT_INET_SERVER
  762. /******************************************************************************
  763.  * initialize AF_INET server, returning a socket that can be listened on.
  764.  ******************************************************************************/
  765. #if !defined(TLI)
  766. static int Initialize_AF_INET_Server_Socket()
  767. {
  768.   int                ls;    /* socket descriptor */
  769.   struct servent    *sp;    /* pointer to service information */
  770.   struct sockaddr_in myaddr_in;    /* for local socket address */
  771.   char* portenv;
  772.  
  773.   /* clear out address structure */
  774.   memset ((char *)&myaddr_in, 0, sizeof(struct sockaddr_in));
  775.   
  776.   /* Set up address structure for the listen socket. */
  777.   myaddr_in.sin_family = AF_INET;
  778.   myaddr_in.sin_addr.s_addr = INADDR_ANY;
  779.   
  780.   /* Find the information for the server to get the needed port number. */
  781.   if (portenv = getenv(DEFAULT_INET_PORT_ENVVAR)) { /* env var for port specification */
  782.     user_prefs.service_port = (int) strtol(portenv, (char **) NULL, 0);    /* environment var overrides Xresource setting */
  783.     myaddr_in.sin_port = htons((u_short) user_prefs.service_port);
  784.   }
  785.   else if (user_prefs.service_port != NULL)
  786.     myaddr_in.sin_port = htons((u_short) user_prefs.service_port);
  787.   else {
  788.     if ((sp = getservbyname(user_prefs.service_name, "tcp")) == NULL)
  789.       xlfatal("Unable to getservbyname() for INET Domain Socket.");
  790.     myaddr_in.sin_port = sp->s_port;
  791.   }
  792.   
  793.   /* Create the listen socket. */
  794.   if ((ls = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  795.     perror(app_name);
  796.     xlfatal("Unable to create INET Domain Socket().");
  797.   }
  798.   
  799.   /* Bind the listen address to the socket. */
  800.   if (bind(ls, &myaddr_in, sizeof(struct sockaddr_in)) == -1) {
  801.     perror(app_name);
  802.     xlfatal("Unable to bind() INET Domain Socket.");
  803.   }
  804.  
  805.   /* Initiate the listen on the socket so remote users
  806.    * can connect.  The listen backlog is set to 5, which
  807.    * is the largest currently supported.
  808.    */
  809.   if (listen(ls,5) == -1) {
  810.     perror(app_name);
  811.     xlfatal("Unable to listen() on INET Domain Socket.");
  812.   }
  813.   
  814.   setpgrp();
  815.  
  816.   fcntl(ls, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  817.   
  818.   return(ls);
  819. }
  820. #else
  821. static int Initialize_AF_INET_Server_Socket()
  822. {
  823.   int listen_fd;
  824.   struct t_bind *bindreq, *bindret;
  825.   struct sockaddr_in *server, raddr;
  826.  
  827.   if ((listen_fd = t_open(TLI_TCP, O_RDWR, NULL)) < 0) {
  828.     t_error("t_open failed for listen_fd");
  829.     exit(1);
  830.   }
  831.  
  832.   if ((bindreq = (struct t_bind *)t_alloc(listen_fd, T_BIND, T_ALL)) == NULL) {
  833.     t_error("t_alloc of t_bind req structure failed");
  834.     exit(2);
  835.   }
  836.  
  837.   if ((bindret = (struct t_bind *)t_alloc(listen_fd, T_BIND, T_ALL)) == NULL) {
  838.     t_error("t_alloc of t_bind ret structure failed");
  839.     exit(2);
  840.   }
  841.  
  842.   server = (struct sockaddr_in *)bindreq->addr.buf;
  843.   server->sin_family = AF_INET;
  844.   server->sin_addr.s_addr = INADDR_ANY;
  845.   if (user_prefs.service_port != NULL)
  846.     server->sin_port = htons(user_prefs.service_port);
  847.   else
  848.     server->sin_port = htons(3914);
  849.   bindreq->qlen = 16;
  850.   bindreq->addr.len = sizeof(struct sockaddr_in);
  851.   bindret->addr.maxlen = sizeof(struct sockaddr_in);
  852.   
  853.   if (t_bind(listen_fd, bindreq, bindret) < 0) {
  854.     t_error("t_bind failed for listen_fd");
  855.     exit(3);
  856.   }
  857.   
  858.   setpgrp();
  859.   
  860.   fcntl(listen_fd, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  861.   
  862.   return(listen_fd);
  863. }
  864. #endif                /* !defined(TLI) */
  865. #endif                /* WINTERP_WANT_INET_SERVER */
  866.  
  867.  
  868. #ifdef WINTERP_WANT_UNIX_SERVER
  869. /******************************************************************************
  870.  * initialize AF_UNIX server, returning a socket that can be listened on.
  871.  * This code contributed by Victor Kan <kan@DG-RTP.DG.COM> and modified by 
  872.  * Niels Mayer.
  873.  ******************************************************************************/
  874. static int Initialize_AF_UNIX_Server_Socket()
  875. {
  876.   int ls;            /* socket descriptor */
  877.   struct sockaddr_un myaddr_un;
  878.   char* socket_path;
  879.  
  880.   memset((char *) &myaddr_un, 0, sizeof(struct sockaddr_un));
  881.   myaddr_un.sun_family = AF_UNIX;
  882.  
  883.   if (socket_path = getenv(DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR)) /* env var for port specification */
  884.     user_prefs.unix_socket_filepath = socket_path;
  885.   /* else user_prefs.unix_socket_filepath is set to DEFAULT_UNIX_SOCKET_FILEPATH value above */
  886.  
  887. #ifndef SOCKADDR_UN_MAXLEN
  888. #define SOCKADDR_UN_MAXLEN 108    /* can't find SOCKADDR_UN_MAXLEN on hpux 7.0, however "char sun_path[108];" */ 
  889. #endif
  890.   if (strlen(user_prefs.unix_socket_filepath) > (SOCKADDR_UN_MAXLEN - 1)) {
  891.     (void) fprintf(stderr, "%s: Error -- socket path %s must be shorter than %d bytes.\n",
  892.            app_name,
  893.            user_prefs.unix_socket_filepath,
  894.            SOCKADDR_UN_MAXLEN - 1);
  895.     exit(1);
  896.   }
  897.   else
  898.     strcpy(myaddr_un.sun_path, user_prefs.unix_socket_filepath);
  899.   
  900.   /*
  901.    * Create the listen socket.
  902.    */
  903.   if ((ls = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  904.     perror(app_name);
  905.     (void) sprintf(temptext, "socket() failed to create Unix Domain socket %s .\n",
  906.            user_prefs.unix_socket_filepath);
  907.     xlfatal(temptext);
  908.   }
  909.  
  910.   /*
  911.    * Bind the listen address to the socket.
  912.    */
  913.   if (bind(ls, &myaddr_un, sizeof(myaddr_un.sun_family) + strlen(myaddr_un.sun_path)) == -1) {
  914.     perror(app_name);
  915.     (void) sprintf(temptext,
  916.            "Unable to bind() Unix Domain socket \"%s\".\n\t\
  917. Note: you may need to do \"rm %s\" if last execution\n\t\
  918. of %s terminated incorrectly. Alternately, another\n\t\
  919. invocation of %smay be running, in which case you need\n\t\
  920. to specify a different UnixDomain Socket file by setting\n\t\
  921. environment variable %s, or by setting\n\t\
  922. resource %s.unixSocketFilepath .\n",
  923.            user_prefs.unix_socket_filepath,
  924.            user_prefs.unix_socket_filepath,
  925.            app_name,
  926.            app_name,
  927.            DEFAULT_UNIX_SOCKET_FILEPATH_ENVVAR,
  928.            app_name);
  929.     xlfatal(temptext);
  930.   }
  931.  
  932.   /*
  933.    * Initiate the listen on the socket so remote users
  934.    * can connect.  The listen backlog is set to 5, which
  935.    * is the largest currently supported.
  936.    */
  937.   if (listen(ls,5) == -1) {
  938.     perror(app_name);
  939.     (void) sprintf(temptext, "Unable to listen() on Unix Domain socket %s .",
  940.            user_prefs.unix_socket_filepath);
  941.     xlfatal(temptext);
  942.   }
  943.   
  944.   setpgrp();
  945.  
  946.   fcntl(ls, F_SETFD, 1);    /* set close-on-exec for the client listener socket */
  947.  
  948.   return(ls);
  949. }
  950. #endif                /* WINTERP_WANT_UNIX_SERVER */
  951.  
  952.  
  953. #ifdef WINTERP_WANT_INET_SERVER
  954. /******************************************************************************
  955.  * Accept the request on client_AF_INET_listen_socket, and open a socket for
  956.  * reading, rdsock. rdsock will be closed by Read_Eval_Print().
  957.  ******************************************************************************/
  958. #if !defined(TLI)
  959. static int Accept_AF_INET_Server_Request(client_listen_socket)
  960.      int client_listen_socket;
  961.   int rdsock;
  962.   int addrlen = sizeof(struct sockaddr_in);
  963.   struct sockaddr_in peeraddr_in; /* for peer socket address */
  964. #ifdef hpux            
  965.   long lingerOpt = 1L;        /* NOTE: necessary while hpux-version < 8.0 (???) */
  966. #else
  967.   struct linger lingerOpt;
  968.   lingerOpt.l_onoff  = 1;
  969.   lingerOpt.l_linger = 10000;
  970. #endif
  971.  
  972.   memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in));
  973.   if ((rdsock = accept(client_listen_socket, &peeraddr_in, &addrlen)) == -1) {
  974.     perror(app_name);
  975.     xlfatal("Unable to accept() on INET Domain Socket."); /* CLEANUP & EXIT */
  976.   }
  977.   if (setsockopt(rdsock, SOL_SOCKET, SO_LINGER, (char *) &lingerOpt,
  978. #ifdef hpux
  979.          sizeof(long)    /* NOTE: necessary while hpux-version < 8.0 (???) */
  980. #else
  981.          sizeof(struct linger)
  982. #endif
  983.          ) == -1) {
  984.     perror(app_name);
  985.     xlfatal("Unable to setsockopt() on INET Domain Socket."); /* CLEANUP & EXIT */
  986.   }
  987.  
  988.   fcntl(rdsock, F_SETFD, 1);    /* set close-on-exec for the client read socket */
  989.  
  990.   return (rdsock);
  991. }
  992. #else
  993. static int Accept_AF_INET_Server_Request(client_listen_socket)
  994.      int client_listen_socket;
  995. {
  996.   int resfd;
  997.   int flags=0;
  998.   struct t_call *call;
  999.  
  1000.   if ((resfd = t_open(TLI_TCP, O_RDWR, NULL)) < 0) {
  1001.     t_error("t_open for responding fd failed");
  1002.     exit(2);
  1003.   }
  1004.  
  1005.   if ((call = (struct t_call *)t_alloc(resfd, T_CALL, T_ALL)) == NULL) {
  1006.     t_error("t_alloc of t_call structure failed");
  1007.     exit(1);
  1008.   }
  1009.   
  1010.   if (t_listen(client_listen_socket, call) < 0) {
  1011.     t_error("t_listen failed for listen_fd");
  1012.     exit(1);
  1013.   }
  1014.  
  1015.   if (t_bind(resfd, NULL, NULL) < 0) {
  1016.     t_error("t_bind failed for responding fd failed");
  1017.     exit(3);
  1018.   }
  1019.  
  1020.   if (t_accept(client_listen_socket, resfd, call) < 0) {
  1021.     if (t_errno == TLOOK) {
  1022.       if (t_rcvdis(client_listen_socket, NULL) < 0) {
  1023.     t_error("t_rcvdis failed for listen_fd");
  1024.     exit(4);
  1025.       }
  1026.       if (t_close(resfd) < 0) {
  1027.     t_error("t_close failed for responding fd");
  1028.     exit(5);
  1029.       }
  1030.       xlfatal("INET connection dropped before we could accept\n");
  1031.       exit(6);
  1032.     }
  1033.     t_error("t_accept failed");
  1034.     exit(7);
  1035.   }
  1036.  
  1037.   t_free(call, T_CALL);
  1038.   return(resfd);
  1039.   
  1040. }
  1041. #endif                /* !defined(TLI) */
  1042. #endif                /* WINTERP_WANT_INET_SERVER */
  1043.  
  1044.  
  1045. #ifdef WINTERP_WANT_UNIX_SERVER
  1046. /******************************************************************************
  1047.  * Accept the request on client_AF_UNIX_listen_socket, and open a socket for
  1048.  * reading, rdsock. rdsock will be closed by Read_Eval_Print().
  1049.  * This code contributed by Victor Kan <kan@DG-RTP.DG.COM> and modified by 
  1050.  * Niels Mayer.
  1051.  ******************************************************************************/
  1052. static int Accept_AF_UNIX_Server_Request(client_listen_socket)
  1053.      int client_listen_socket;
  1054.   int rdsock;
  1055.   struct sockaddr_un peeraddr_un;
  1056.   int addrlen = sizeof (struct sockaddr_un);
  1057.   memset ((char *) &peeraddr_un, 0, sizeof (struct sockaddr_un));
  1058.  
  1059.   if ((rdsock = accept(client_listen_socket, &peeraddr_un, &addrlen)) == -1) {
  1060.     perror(app_name);
  1061.     xlfatal("Unable to accept() on Unix Domain socket."); /* cleanup and exit */
  1062.   }
  1063.  
  1064.   fcntl(rdsock, F_SETFD, 1);    /* set close-on-exec for the client read socket */
  1065.  
  1066.   return (rdsock);
  1067. }
  1068. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1069.  
  1070.  
  1071. #ifdef WINTERP_WANT_INET_SERVER
  1072. /******************************************************************************
  1073.  * This procedure is called (indirectly, via AtAppAddInput() callback) from 
  1074.  * XtAppNextEvent() in main() and from XtAppNextEvent() in 
  1075.  * xldbug.c:breakloop(). This callback will be called whenever new input 
  1076.  * appears on client_AF_INET_listen_socket indicating that a new connection has been 
  1077.  * requested and that another s-expression is ready to be evaluated by Xlisp. 
  1078.  * This procedure will accept that connection and read all the data from the 
  1079.  * client and send it off to the XLisp reader, and the Xlisp evaluator. 
  1080.  * The results of the evaluation are printed.
  1081.  ******************************************************************************/
  1082. static void AF_INET_Read_Eval_Print(client_data, source_fildes, id)
  1083.      caddr_t    client_data;
  1084.      int*       source_fildes;
  1085.      XtInputId* id;
  1086. {
  1087.   Read_Eval_Print(Accept_AF_INET_Server_Request(client_AF_INET_listen_socket));
  1088. }
  1089. #endif                /* WINTERP_WANT_INET_SERVER */
  1090.  
  1091. #ifdef WINTERP_WANT_UNIX_SERVER
  1092. /******************************************************************************
  1093.  * This procedure is called (indirectly, via AtAppAddInput() callback) from 
  1094.  * XtAppNextEvent() in main() and from XtAppNextEvent() in 
  1095.  * xldbug.c:breakloop(). This callback will be called whenever new input 
  1096.  * appears on client_AF_UNIX_listen_socket indicating that a new connection has been 
  1097.  * requested and that another s-expression is ready to be evaluated by Xlisp. 
  1098.  * This procedure will accept that connection and read all the data from the 
  1099.  * client and send it off to the XLisp reader, and the Xlisp evaluator. 
  1100.  * The results of the evaluation are printed.
  1101.  ******************************************************************************/
  1102. static void AF_UNIX_Read_Eval_Print(client_data, source_fildes, id)
  1103.      caddr_t    client_data;
  1104.      int*       source_fildes;
  1105.      XtInputId* id;
  1106. {
  1107.   Read_Eval_Print(Accept_AF_UNIX_Server_Request(client_AF_UNIX_listen_socket));
  1108. }
  1109. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1110.  
  1111.  
  1112. /******************************************************************************
  1113.  * This procedure is called from AF_UNIX_Read_Eval_Print() or
  1114.  * AF_INET_Read_Eval_Print(). Those procedures will accept the connections
  1115.  * requested on client_AF_UNIX_listen_socket or client_AF_INET_listen_socket
  1116.  * and return a read-socket <rdsock> from which this procedure will
  1117.  * read all the data from the client and send it off to the XLisp reader,
  1118.  * and the Xlisp evaluator.  The results of the evaluation are printed.
  1119.  ******************************************************************************/
  1120. static void Read_Eval_Print(rdsock)
  1121.      int rdsock;
  1122. {
  1123.   static char rdbuf[BUFSIZ];
  1124.   int len, i;
  1125.   LVAL sexp_stream, new_elt, last_elt = NIL;
  1126. #if defined(TLI)
  1127.   int flags=0;
  1128. #endif
  1129.  
  1130.   /* 
  1131.    * set this global flag so that main() and breakloop() will set up an error 
  1132.    * handler for the next call to the lisp evaluator.
  1133.    */
  1134.   read_eval_print_just_called = TRUE; 
  1135.  
  1136.   /*
  1137.    * Read the sexpression from the socket -- note assumption that entire
  1138.    * sexpression is sent in one "packet" and then the socket is closed.
  1139.    */
  1140.  
  1141.   xlsave1(sexp_stream);        /* protect from gc */
  1142.   sexp_stream = newustream();    /* note - stream obj has ptrs for head and tail*/
  1143.  
  1144. #if !defined(TLI)  
  1145.   while (len = recv(rdsock, rdbuf, BUFSIZ, 0)) { /* read len characters into rdbuf */
  1146.     if (len < 0) {
  1147.       perror(app_name);
  1148.       xlfatal("Unable to recv() on read socket."); /* CLEANUP & EXIT */
  1149.     }
  1150. #else
  1151.   for (;;) {
  1152.     len = t_rcv(rdsock, rdbuf, BUFSIZ, &flags);
  1153.     if (len < 0) {
  1154.       if (t_errno == TLOOK)
  1155.     if (t_look(rdsock) == T_ORDREL)
  1156.       break;
  1157.       t_error(app_name);
  1158.       xlfatal("Unable to recv() on read socket."); /* CLEANUP & EXIT */
  1159.     }
  1160. #endif    /* !defined(TLI) */
  1161.  
  1162.     /* foreach character received, stuff it into an xlisp unnamed stream */
  1163.     for (i = 0; i < len; i++) {
  1164.       new_elt = cons(cvchar(rdbuf[i]), NIL);
  1165.       if (last_elt) {        /* if we've already created the head of the stream */
  1166.     rplacd(last_elt, new_elt); /* add new_elt to the tail of the list */
  1167.     last_elt = new_elt;    /* increment last_elt pointer */
  1168.       }
  1169.       else {            /* else create the head of the stream */
  1170.     sethead(sexp_stream, new_elt);
  1171.     last_elt = new_elt;
  1172.       }
  1173.     }
  1174.   }
  1175. #if defined(TLI)
  1176.     t_close(rdsock);        /* we've finished reading from the socket */
  1177. #else
  1178.     close(rdsock);
  1179. #endif /* TLI */
  1180.     
  1181.   if (last_elt)
  1182.     settail(sexp_stream, last_elt); /* streams are cdr-coded -- give ptr to tail */
  1183.   else            
  1184.     sexp_stream = NIL;        /* loop never executed, no characters read. */
  1185.   lisp_reader_hit_eof = !(Read_From_Stream_Eval_And_Print(sexp_stream));
  1186.   xlpop();            /*sexp_stream*/
  1187.  
  1188.  
  1189.   /* TODO -- 
  1190.      (1) make the client program, wl, wait until the evaluation is done. This will
  1191.      ensure that we don't get into a "race condition" with gnumeacs' winterp-mode --
  1192.      It is possible that winterp will still be reading winterp-mode's tempfile
  1193.      as gnuemacs writes another copy of this file. This can happen when a user
  1194.      is giving the gnuemacs winterp-send-defun command faster than winterp can
  1195.      read the files being sent to it.
  1196.      
  1197.      (2) send the results of the evaluation back to the client program wl, 
  1198.      have it print the results on stdout. Furthermore, if the form sent to
  1199.      winterp by wl results in a lisp error, wl should return a nonzero exitstatus. 
  1200.      
  1201.      This would be trivial, except that we'd want to send stdout and stderr
  1202.      back as well. If we were to use only the xlisp xlio.c routiunes for printing
  1203.      We could conceivably set the lisp symbols *standard-output* *debug-output*
  1204.      and *trace-output* so that they print to a stream, and just shove these
  1205.      streams back at the client.
  1206.      */
  1207.  
  1208.   /*
  1209.    * HACK CAUSED BY LAME IMPLEMENTATION OF XtMainLoop/XtAppNextEvent:
  1210.    * This creates a bogus event so as to force XtAppNextEvent to return, even if
  1211.    * the lisp evaluation didn't result in any new events being generated. 
  1212.    * The problem was that AtAppAddInput callbacks were being handled entirely 
  1213.    * within XtAppNextEvent(). Thus, once this procedure exited, XtAppNextEvent() 
  1214.    * would block waiting for a "real event", and never exit until an XEvent 
  1215.    * occured. XLISP requires that a new setjmp/longjmp error return be setup 
  1216.    * before each new lisp evaluation, and that couldn't happen unless 
  1217.    * XtAppNextEvent exited and allowed a new execution context to be created.
  1218.    *
  1219.    * Although I could do a call to XEventsQueued(display, QueuedAfterFlush)
  1220.    * in order to determine whether a bogus event needs to be sent, my hunch
  1221.    * is that the extra XFlush() caused by that operation would be more 
  1222.    * inefficient than processing/discarding the extra bogus event each time
  1223.    * a sexp is sent to the lisp server.
  1224.    */
  1225.   {
  1226.     XEvent bogus_event;
  1227.     bogus_event.type = 0;    /* XAnyEvent type --> ignored by XtDispatchEvent() */
  1228.     bogus_event.xany.display = display;
  1229.     bogus_event.xany.window  = XtWindow(toplevel_Wgt);;
  1230.     XPutBackEvent(display, &bogus_event);
  1231.   }
  1232. }
  1233.  
  1234.  
  1235. /*******************************************************************************
  1236.  * This fn reads from its input, which is assumed to be a xlisp stream.
  1237.  * returns false if EOF hit during read.
  1238.  ******************************************************************************/
  1239. static int Read_From_Stream_Eval_And_Print(sexp_stream)
  1240.      LVAL sexp_stream;        /* make sure this is a stream, and not other LVAL */
  1241. {
  1242.   extern int xldebug;
  1243.   extern LVAL s_1plus,s_2plus,s_3plus,s_1star,s_2star,s_3star,s_minus;
  1244.   LVAL rep_expr;
  1245.   int read_result;
  1246.  
  1247.   xlprot1(sexp_stream);        /* protect against GC */
  1248.     
  1249.   /* Read Evaluate and Print the expression in sexp_stream */
  1250.   if ((read_result = xlread(sexp_stream, &rep_expr, FALSE))) {
  1251.  
  1252.     /* save the last expression returned by the reader */
  1253.     setvalue(s_3plus, getvalue(s_2plus));
  1254.     setvalue(s_2plus, getvalue(s_1plus));
  1255.     setvalue(s_1plus, getvalue(s_minus));
  1256.     setvalue(s_minus, rep_expr);
  1257.  
  1258.     /* evaluate the expression returned by the reader */
  1259.     rep_expr = xleval(rep_expr);
  1260.  
  1261.     /* save the last expression returned by the evaluator */
  1262.     setvalue(s_3star,getvalue(s_2star));
  1263.     setvalue(s_2star,getvalue(s_1star));
  1264.     setvalue(s_1star,rep_expr);
  1265.  
  1266.     if (xldebug)        /* print eval results */
  1267.       dbgprint(rep_expr);
  1268.     else
  1269.       stdprint(rep_expr);
  1270.   }
  1271.  
  1272.   else {            /* if reader hit EOF, just print a new line */
  1273.     if (xldebug)
  1274.       dbgputstr("\n");   
  1275.     else
  1276.       stdputstr("\n");
  1277.   }
  1278.   xlpop(/*sexp_stream*/);
  1279.   return (read_result);        /* return FALSE if hit EOF */
  1280. }
  1281.  
  1282.  
  1283. /*******************************************************************************
  1284.  * xlfatal - print a fatal error message and exit
  1285.  ******************************************************************************/
  1286. xlfatal(msg)
  1287.   char *msg;
  1288. {
  1289.   extern FILE *tfp;
  1290.  
  1291.   (void) fprintf(stderr, "%s -- error: %s\n", app_name, msg);
  1292.  
  1293. #ifdef WINTERP_WANT_INET_SERVER
  1294.   if (client_AF_INET_listen_socket)
  1295.     close(client_AF_INET_listen_socket);
  1296. #endif                /* WINTERP_WANT_INET_SERVER */
  1297.  
  1298. #ifdef WINTERP_WANT_UNIX_SERVER
  1299.   if (client_AF_UNIX_listen_socket) {
  1300.     close(client_AF_UNIX_listen_socket);
  1301.     unlink(user_prefs.unix_socket_filepath);
  1302.   }
  1303. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1304.  
  1305.   if (tfp)
  1306.     fclose(tfp);
  1307.  
  1308.   if (app_context)
  1309.     XtDestroyApplicationContext(app_context);
  1310.  
  1311.   exit(1);
  1312. }
  1313.  
  1314.  
  1315. /*******************************************************************************
  1316.  * wrapup - clean up and exit to the operating system. 
  1317.  * This is also called in xlsys.c:xexit().
  1318.  ******************************************************************************/
  1319. wrapup()
  1320. {
  1321.   extern FILE *tfp;
  1322.  
  1323.   stdputstr("\n");
  1324.  
  1325. #ifdef WINTERP_WANT_INET_SERVER
  1326.   if (client_AF_INET_listen_socket)
  1327.     close(client_AF_INET_listen_socket);
  1328. #endif                /* WINTERP_WANT_INET_SERVER */
  1329.  
  1330. #ifdef WINTERP_WANT_UNIX_SERVER
  1331.   if (client_AF_UNIX_listen_socket) {
  1332.     close(client_AF_UNIX_listen_socket);
  1333.     unlink(user_prefs.unix_socket_filepath);
  1334.   }
  1335. #endif                /* WINTERP_WANT_UNIX_SERVER */
  1336.  
  1337.   if (tfp)
  1338.     fclose(tfp);
  1339.  
  1340.   if (app_context)
  1341.     XtDestroyApplicationContext(app_context);
  1342.  
  1343.   exit(0);
  1344. }
  1345.  
  1346. /*******************************************************************************
  1347.  * This is the protocol callback for application shells created in WINTERP.
  1348.  * see toplevel_Wgt above, and also APPLICATION_SHELL_WIDGET_CLASS in
  1349.  * wc_SHELL.c.
  1350.  ******************************************************************************/
  1351. void Winterp_Application_Shell_WMDelete_Callback(shell, closure, call_data)
  1352.      Widget shell;
  1353.      XtPointer closure;
  1354.      XtPointer call_data;
  1355. {
  1356.   wrapup();
  1357. }
  1358.  
  1359. /*******************************************************************************
  1360.  * This handles fatal errors from the Xtoolkit. According to the Xtoolkit
  1361.  * docs, such a handler should terminate the application. In this case,
  1362.  * however, we suggest to the user that the application be terminated, but
  1363.  * don't actually do it. This may allow the user to figure out what went 
  1364.  * wrong by poking around inside the lisp environment.
  1365.  *
  1366.  * This is set up in main() via XtAppSetErrorHandler(). Note that the default
  1367.  * error handler is _XtDefaultError().
  1368.  ******************************************************************************/
  1369. static void Winterp_Xtoolkit_Error_Handler(message)
  1370.      String message;
  1371. {
  1372.   (void) sprintf(temptext,
  1373.          "X Toolkit Fatal Error -- PLEASE QUIT AND RESTART THIS APPLICATION:\n\t%s\n",
  1374.          message);
  1375.   xlfail(temptext);
  1376. }
  1377.  
  1378.  
  1379. /*******************************************************************************
  1380.  * This handles nonfatal errors from the Xtoolkit.
  1381.  *
  1382.  * This is set up in main() via XtAppSetWarningHandler(). Note that the default
  1383.  * error handler is _XtDefaultWarning().
  1384.  ******************************************************************************/
  1385. static void Winterp_Xtoolkit_Warning_Handler(message)
  1386.      String message;
  1387. {
  1388.   (void) sprintf(temptext,
  1389.          "X Toolkit Warning:\n\t%s\n",
  1390.          message);
  1391.   xlfail(temptext);
  1392. }
  1393.  
  1394.  
  1395. /*******************************************************************************
  1396.  * The following code is from X11r4:mit/lib/X/XlibInt.c.
  1397.  * Copyright    Massachusetts Institute of Technology    1985, 1986, 1987.
  1398.  ******************************************************************************/
  1399. static int Winterp_XPrintDefaultError (dpy, event, fp)
  1400.     Display *dpy;
  1401.     XErrorEvent *event;
  1402.     FILE *fp;
  1403. {
  1404.     char buffer[BUFSIZ];
  1405.     char mesg[BUFSIZ];
  1406.     char number[32];
  1407.     char *mtype = "XlibMessage";
  1408.     register _XExtension *ext = (_XExtension *)NULL;
  1409.     XGetErrorText(dpy, event->error_code, buffer, BUFSIZ);
  1410.     XGetErrorDatabaseText(dpy, mtype, "XError", "X Error", mesg, BUFSIZ);
  1411.     (void) fprintf(fp, "%s:  %s\n  ", mesg, buffer);
  1412.     XGetErrorDatabaseText(dpy, mtype, "MajorCode", "Request Major code %d", 
  1413.     mesg, BUFSIZ);
  1414.     (void) fprintf(fp, mesg, event->request_code);
  1415.     if (event->request_code < 128) {
  1416.     sprintf(number, "%d", event->request_code);
  1417.     XGetErrorDatabaseText(dpy, "XRequest", number, "", buffer, BUFSIZ);
  1418.     } else {
  1419.     for (ext = dpy->ext_procs;
  1420.          ext && (ext->codes.major_opcode != event->request_code);
  1421.          ext = ext->next)
  1422.       ;
  1423.     if (ext)
  1424.         strcpy(buffer, ext->name);
  1425.     else
  1426.         buffer[0] = '\0';
  1427.     }
  1428.     (void) fprintf(fp, " (%s)\n  ", buffer);
  1429.     XGetErrorDatabaseText(dpy, mtype, "MinorCode", "Request Minor code %d",
  1430.     mesg, BUFSIZ);
  1431.     (void) fprintf(fp, mesg, event->minor_code);
  1432.     if (ext) {
  1433.     sprintf(mesg, "%s.%d", ext->name, event->minor_code);
  1434.     XGetErrorDatabaseText(dpy, "XRequest", mesg, "", buffer, BUFSIZ);
  1435.     (void) fprintf(fp, " (%s)", buffer);
  1436.     }
  1437.     fputs("\n  ", fp);
  1438.     XGetErrorDatabaseText(dpy, mtype, "ResourceID", "ResourceID 0x%x",
  1439.     mesg, BUFSIZ);
  1440.     (void) fprintf(fp, mesg, event->resourceid);
  1441.     fputs("\n  ", fp);
  1442.     XGetErrorDatabaseText(dpy, mtype, "ErrorSerial", "Error Serial #%d", 
  1443.     mesg, BUFSIZ);
  1444.     (void) fprintf(fp, mesg, event->serial);
  1445.     fputs("\n  ", fp);
  1446.     XGetErrorDatabaseText(dpy, mtype, "CurrentSerial", "Current Serial #%d",
  1447.     mesg, BUFSIZ);
  1448.     (void) fprintf(fp, mesg, dpy->request);
  1449.     fputs("\n", fp);
  1450.     if (event->error_code == BadImplementation) return 0;
  1451.     return 1;
  1452. }
  1453.  
  1454.  
  1455. /*******************************************************************************
  1456.  * This handles errors from Xlib. It is set up in main() via XSetErrorHandler().
  1457.  *
  1458.  * By default, the Xlib error handler is:
  1459.  *
  1460.  * int _XDefaultError(dpy, event)
  1461.  *     Display *dpy;
  1462.  *     XErrorEvent *event;
  1463.  * {
  1464.  *     if (_XPrintDefaultError (dpy, event, stderr) == 0) return 0;
  1465.  *     exit(1);
  1466.  * }
  1467.  *
  1468.  * However for WINTERP, we don't want to have exit() called on such errors,
  1469.  * rather we call xlfail() to indicate an error occured and to throw us into
  1470.  * the debug loop.
  1471.  ******************************************************************************/
  1472. static int Winterp_Xlib_Error_Handler(dpy, event)
  1473.      Display*     dpy;
  1474.      XErrorEvent* event;
  1475. {
  1476.  
  1477.   (void) Winterp_XPrintDefaultError (dpy, event, stderr);
  1478.   xlfail("Xlib error detected.");
  1479.   return (0);
  1480. }
  1481.